﻿using CaseManagerLibrary.Models;
using CaseManagerLibrary.Socket;
using PSDClientService.SystemSettings;
using PSDLib;
using PSDLib.Models;
using PSDLib.Protocols;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace PSDClientService
{
    public class HeartbeatManager
    {
        private Thread heartbeatThread = null;

        private ClientServiceContext context;

        private bool connectServerFail = false;
        private DateTime firstDisconnectServerTime;

        public HeartbeatManager(ClientServiceContext ctx)
        {
            context = ctx;
        }

        /// <summary>
        /// 启动心跳线程
        /// </summary>
        public void Start()
        {
            context.Running = true;
            heartbeatThread = new Thread(new ThreadStart(SendHeartBeat));
            heartbeatThread.Start();
        }

        /// <summary>
        /// 执行发送心跳，更新设备状态到服务端
        /// </summary>
        private void SendHeartBeat()
        {
            HResult result = null;

            while (context.Running)
            {
                context.DeviceManager.UpdateLocalStorage();

                var msg = new PSDHeartBeatMessage() { Heartbeart = new PSDHeartbeat() };
                msg.Heartbeart.DeviceId = context.Device.id;
                msg.Heartbeart.DeviceIP = context.Device.device_ip;
                msg.Heartbeart.DevicePort = context.Device.device_port;
                msg.Heartbeart.DeviceInfo = context.Device;

                //msg.Heartbeart.DownloadState = (context.Downloading ? 1 : 0);
                //msg.Heartbeart.BurnState = 0;
                //msg.Heartbeart.MainStorage = context.Device.main_storage;
                //msg.Heartbeart.MainStorageTotal = context.Device.main_storage_total;
                //msg.Heartbeart.MainStorageFree = context.Device.main_storage_free;
                //msg.Heartbeart.SecondaryStorage = context.Device.second_storage;
                //msg.Heartbeart.SecondaryStorageTotal = context.Device.second_storage_total;
                //msg.Heartbeart.SecondaryStorageFree = context.Device.second_storage_free;

                result = context.MessageManager.SendToServer(msg);

                if (AppSettings.Setting.DisconnectServerTimeout > 0)
                {
                    if (result.success)
                    {
                        connectServerFail = false;
                    }
                    else
                    {
                        if (!connectServerFail)
                        {
                            //如果是首次无法访问PSD Server,则设置连接失败标志，并记录首次失败时间
                            connectServerFail = true;
                            firstDisconnectServerTime = DateTime.Now;
                        }

                        if ((DateTime.Now - firstDisconnectServerTime).TotalMinutes > AppSettings.Setting.DisconnectServerTimeout)
                        {
                            //如果当前时间与首次连接失败时间已经超过服务器连接超时上限
                            //先检查系统奔溃重启机制的先决条件是否成立
                            if (CheckCrashRebootCondition())
                            {
                                CreateCrashFile(firstDisconnectServerTime, AppSettings.Setting.DisconnectServerTimeout);

                                context.DeviceManager.RebootDevice(DeviceRebootType.无法连接服务器重启);
                            }
                            else
                            {
                                string path = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "PSD", "Log", DeviceRebootType.无法连接服务器重启.ToString() + ".log");
                                var sw = System.IO.File.AppendText(path);
                                string log = $@"{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} 重启次数达到MaxCrashRebootTimes上限({AppSettings.Setting.MaxCrashRebootTimes}次)，强制结束服务进程";
                                sw.WriteLine(log);
                                sw.Close();

                                context.KillService();
                            }
                        }
                    }
                }

                Thread.Sleep(20 * 1000);
            }
        }

        private bool CheckCrashRebootCondition()
        {
            //判断log目录中记录失败崩溃的crash_time.log文件的数量是否超过上限

            string path = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "PSD", "Log");

            string[] files = System.IO.Directory.GetFiles(path);

            int count = 0;
            foreach (string file in files)
            {
                if (file.StartsWith(path + "\\crash_") && file.EndsWith(".log"))
                {
                    count += 1;
                }
            }

            return count < AppSettings.Setting.MaxCrashRebootTimes;
        }

        private void CreateCrashFile(DateTime firstFailTime, int timeout)
        {
            //在log目录中创建一个记录失败崩溃的crash_time.log文件
            string path = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "PSD", "Log", "crash_" + firstFailTime.ToString("yyyyMMddHHmmss") + ".log");
            var sw = System.IO.File.AppendText(path);
            string log = $@"自{firstFailTime.ToString("yyyy-MM-dd HH:mm:ss")}起无法连接PSD Server超过{timeout}分钟，设备重启";
            sw.WriteLine(log);
            sw.Close();
        }

        private void ClearCrashFiles()
        {
            //重命名所有log目录中的crash_time.log文件，将这些文件设置为忽略状态
            string path = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "PSD", "Log");

            string[] files = System.IO.Directory.GetFiles(path);

            int count = 0;
            foreach (string file in files)
            {
                if (file.StartsWith(path + "\\crash_") && file.EndsWith(".log"))
                {
                    string newFile = file.Replace(path + "\\crash_", path + "\\ignore_crash_");

                    System.IO.File.Move(file, newFile);

                    var sw = System.IO.File.AppendText(newFile);
                    string log = $@"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} 已忽略该crash文件";
                    sw.WriteLine(log);
                    sw.Close();
                }
            }
        }

        /// <summary>
        /// 停止发送心跳
        /// </summary>
        public void Stop()
        {
            try
            {
                context.Running = false;
                heartbeatThread.Abort();
            }
            catch
            { }

        }
    }
}
